package com.xb.loan.cashier.biz.service.impl;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.xb.loan.cashier.biz.dao.CashierEncashOrderDao;
import com.xb.loan.cashier.biz.dao.bean.CashierEncashBatch;
import com.xb.loan.cashier.biz.dao.bean.CashierEncashOrder;
import com.xb.loan.cashier.biz.dao.bean.CashierPayChannelBank;
import com.xb.loan.cashier.biz.dao.bean.CashierPayChannelType;
import com.xb.loan.cashier.biz.service.CashierEncashBatchService;
import com.xb.loan.cashier.biz.service.CashierEncashOrderService;
import com.xb.loan.cashier.biz.service.CashierPayChannelBankService;
import com.xb.loan.cashier.biz.service.CashierPayChannelTypeService;
import com.xb.loan.cashier.biz.util.Configure;
import com.xb.loan.cashier.biz.util.FileUtil;
import com.xb.loan.cashier.service.constant.ICashierEnumConst;
import com.xb.loan.cashier.service.exception.ICashierServiceException;
import com.xb.loan.encryptor.crypt.Encryptor;
import com.xb.loan.encryptor.crypt.EncryptorManager;
import com.xb.loan.fund.service.ICashEncashService;
import com.xb.loan.fund.service.bean.EncashResultVO;
import com.xb.loan.log.exception.BizException;
import com.xb.loan.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

@Service("cashierEncashOrderService")
public class CashierEncashOrderServiceImpl implements CashierEncashOrderService,ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(CashierEncashOrderServiceImpl.class);
    protected ApplicationContext ctx;
    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        this.ctx = ctx;
    }
    @Autowired
    private CashierEncashOrderDao cashierEncashOrderDao;
    @Autowired
    private CashierEncashBatchService cashierEncashBatchService;
    @Autowired
    private CashierPayChannelBankService cashierPayChannelBankSevice;
    @Autowired
    private CashierPayChannelTypeService cashierPayChannelTypeService;
    
    private ICashEncashService cashEncashService;
    

    @Override
    public void insert(CashierEncashOrder order) {
        cashierEncashOrderDao.insert(order);
    }
    

    @Override
    public CashierEncashOrder selectByOrderId(String orderId) {
        return cashierEncashOrderDao.selectByOrderId(orderId);
    }

    @Override
    public int initEncashOrder(String cashierOrderId, int paychannelType, String batchId) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("cashierOrderId", cashierOrderId);
        params.put("paychannelType", paychannelType);
        params.put("batchId", batchId);
        return cashierEncashOrderDao.initEncashOrder(params);
    }

    @Override
    @Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
    public int initFirstEncashOrder(String cashierOrderId, String payChannelId, int paychannelType, String bankCode, String batchId) {
        CashierEncashBatch cashierEncashBatch = new CashierEncashBatch();
        cashierEncashBatch.setBatchId(batchId);
        cashierEncashBatch.setBankCodePlat(bankCode);
        cashierEncashBatch.setCount(1);
        cashierEncashBatch.setPaychannelType(paychannelType);
        cashierEncashBatch.setPayChannelId(payChannelId);
        cashierEncashBatch.setStatus(ICashierEnumConst.CashierEncashBatchStatus.WAIT.getStatus());
        cashierEncashBatch.setCreateTime(new Date());
        cashierEncashBatchService.insert(cashierEncashBatch);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("cashierOrderId", cashierOrderId);
        params.put("paychannelType", paychannelType);
        params.put("batchId", batchId);
        int row = cashierEncashOrderDao.initEncashOrder(params);
        return row;
    }

    @Override
    public List<CashierPayChannelType> selectChannel(String sellBank) {
        if(StringUtils.isBlank(sellBank)){
            return null;
        }
        // 1.根据银行获取所有支持的渠道
        List<CashierPayChannelBank> banks = cashierPayChannelBankSevice.getByBankCodePlat(sellBank);
        if(banks==null || banks.size()<1){
            return null;
        }
        // 确保查询到的数据在数据库中存在
        List<CashierPayChannelType> channelTypes = new ArrayList<CashierPayChannelType>();
        CashierPayChannelType channelType = null;
        for(CashierPayChannelBank bank : banks){
            channelType = cashierPayChannelTypeService.getByPaychannelType(bank.getPaychannelType());
            if(channelType!=null){
                channelTypes.add(channelType);
            }
        }
        if(channelTypes==null || channelTypes.size()<1){
            return null;
        }
        // 2.获取渠道
        return channelTypes;//DefaultChannelSelectorFactory.getInstance().getSelector().select(channelTypes);
    }

    @Override
    public List<CashierEncashOrder> selectEncashOrders(int status, String bankCodePlat, Date endTime, int pageNo, int pageSize) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("status", status);
        params.put("bankCodePlat", bankCodePlat);
        params.put("endTime", endTime);
        params.put("from", (pageNo-1)*pageSize);
        params.put("size", pageSize);
        return cashierEncashOrderDao.selectEncashOrders(params);
    }

    @Override
    public int selectBatchCount(String batchId) {
        return cashierEncashOrderDao.selectBatchCount(batchId);
    }

    @Override
    public List<CashierEncashOrder> selectBatchOrders(String batchId, int pageNo, int pageSize) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("batchId", batchId);
        params.put("from", (pageNo-1)*pageSize);
        params.put("size", pageSize);
        return cashierEncashOrderDao.selectBatchOrders(params);
    }
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
    	String payUrl = "231?21?";
    	System.out.println(payUrl.replace("?",""));
	}
    @Override
    public void updateEncashResultFile(String filePath, String fileName) throws UnsupportedEncodingException, FileNotFoundException {
        String newFile = filePath+"/"+fileName;
        newFile = newFile.replace("//", "/");//去掉重复的标签
    	File file = new File(filePath+"/"+fileName);
        // 付款日期,处理日期,总笔数,处理成功笔数,处理失败笔数,成功付款总金额,失败付款总金额,支付宝帐号(Email)
        // 20150908,20150908,2,0,2,0.00,0.02,service@lingcaibao.com
        // 商户流水号,收款银行户名,收款银行帐号,收款开户银行,收款银行所在省份,收款银行所在市,收款支行名称,金额,对公对私标志,成功失败标志,提现流水号,是否退票,备注,原备注
        // 1,N,N,100,,,,0.01,2,F,NA,0,"收款银行户名的长度不正确,必须在1到60个字符之间|收款银行帐号长度必须在1-30个字符的半角数字|非直连银行省市支行信息不完全",
        if(!file.exists()){
            logger.warn("updateEncashResultFile msg=file not exist! file="+filePath+"/"+fileName);
            return;
        }
        
        try {
            String line = null;
            List<String> list = FileUtil.readFileByLine(file, "GBK");
            
            if(CollectionUtils.isEmpty(list)){
                logger.warn("updateEncashResultFile msg=file is empty! file="+filePath+"/"+fileName);
                return;
            }
            Date tradeDay = new SimpleDateFormat("yyyyMMdd").parse(list.get(1).split(",")[1]);
            for(int i=3;list!=null&&i<list.size();i++){
                String orderId = null;
                String statusStr = null;
                String msg = null;
                try {
                    line = list.get(i);
                    if(StringUtils.isBlank(line)){
                        break;
                    }
                    String[] values = line.split(",");
                    orderId = values[0];
                    statusStr = values[9];
                    boolean success = "S".equals(statusStr);//S：处理成功  F：处理失败   P：处理中  DISUSE：已废除
                    int status = success? ICashierEnumConst.CashierEncashStatus.SUCCESS.getStatus():ICashierEnumConst.CashierEncashStatus.FAIL.getStatus();
                    if ("F".equals(statusStr)) {
						msg = values[12];
					}
                    updateEncashResult(orderId, status, tradeDay,msg);
                    pushEncashOrder(orderId);
                } catch (Exception e) {
                    logger.warn("updateEncashResultFile cashierOrderId="+orderId+" status="+statusStr+" msg=回推失败 ");
                }
            }
            cashierEncashBatchService.updateToFinish(fileName);
        } catch (Exception e) {
            logger.error("系统异常!", e);
        }
    }
    
    @Override
    public int updateEncashResult1(String orderId, int status, Date tradeDay){
        logger.info("msg=对账文件为成功，数据库为处理中，已对账文件状态为准!!!"+" orderId="+orderId);
        return updateEncashResult(orderId, status, tradeDay,null);
    }
    
    @Override
    public int updateEncashResult(String orderId, int status, Date tradeDay, String msg){
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("orderId", orderId);
        params.put("status", status);
        params.put("tradeDay", tradeDay);
        params.put("msg", msg);
        return cashierEncashOrderDao.updateEncashResult(params);
    }

    @Override
    public int refundEncashResult(String orderId, String day) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("orderId", orderId);
        params.put("day", day);
        // 重置推送状态   推送次数
        return cashierEncashOrderDao.refundEncashResult(params);
    }

    @Override
    public List<CashierEncashOrder> selectPushOrders(Date sendTime, int maxPushCount, int pageNo, int pageSize) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pushTime", sendTime);
        params.put("maxPushCount", maxPushCount);
        params.put("from", (pageNo-1)*pageSize);
        params.put("size", pageSize);
        return cashierEncashOrderDao.selectPushOrders(params);
    }

    @Override
    public void pushEncashOrder(String orderId) throws BizException {
        CashierEncashOrder order = cashierEncashOrderDao.selectByOrderId(orderId);
        pushEncashOrder(order);
    }
    
    @Override
    public void pushEncashOrder(CashierEncashOrder order) throws BizException {
        String orderId = null;
        
        try {
            if(order==null){
                logger.warn("pushEncashOrder msg=提现订单不存在 ");
                throw ICashierServiceException.ORDER_NOT_EXIST;
            }
            orderId = order.getOrderId();
            int status = order.getStatus();
            String platId = order.getPlatId();
            String userId = order.getUserId();
            String partnerId = order.getPartnerId();
            double money = order.getMoney();
            DecimalFormat df = new DecimalFormat("#0.00");
            String moneyStr = df.format(money);
            
            // 验证数据库数据是否被篡改
            if(!validateEncashSign(order)){
                logger.warn("pushEncashOrder orderId="+orderId+" status="+status+" msg=校验数据库数据失败 ");
                throw ICashierServiceException.VALIDATE_ERROR;
            }
            
            if(status< ICashierEnumConst.CashierEncashStatus.SUCCESS.getStatus()){
                logger.info("pushEncashOrder orderId="+orderId+" status="+status+" msg=订单未处理完成 ");
                throw ICashierServiceException.ORDER_NOT_FINISH_ERROR;
            }
            String returnCode = status== ICashierEnumConst.CashierEncashStatus.SUCCESS.getStatus()?"1":"2";
            // 用收银台私钥加密
            String sign = genEncashSign(order.getOrderId(), platId, userId, partnerId, moneyStr, returnCode);
            EncashResultVO encashVO =new EncashResultVO();
            encashVO.setEncashId(orderId);
            encashVO.setForeignId(order.getCashierOrderId());
            encashVO.setMoney(money);
            encashVO.setPlatId(platId);
            encashVO.setReturnCode(returnCode);
            encashVO.setUserId(userId);
            encashVO.setDigitalSign(sign);
            // 回推给业务系统
            cashEncashService = (ICashEncashService)ctx.getBean("cashEncashService");
            cashEncashService.encashResult(encashVO);
            // 更新回推成功状态
            cashierEncashOrderDao.updatePushSuccess(orderId);
        } catch (Exception e) {
        	 logger.error("pushEncashOrder 异常", e);
            // 更新回推失败状态
        	int maxPushCount = Configure.getIntValue("job.platpush.maxCount");
            if(StringUtils.isNotBlank(orderId)){
            	int res = 0;
            	try {
					if(order.getPushCount() >= maxPushCount - 1){  //查过了最大推送次数
						logger.warn("提现订单："+orderId+" 推送  pushEncashOrder 失败，当前推送次数为："+order.getPushCount() + " ---> 推送结果失败");
						res = cashierEncashOrderDao.updatePushFail(orderId);  // 更新推送失败
						if (res<=0) {
							logger.info("更新提现推送状态失败！orderId="+orderId+",pushCount="+order.getPushCount());
						}
					}else{
						logger.warn("提现订单："+orderId+" 推送  pushEncashOrder 失败 ，当前推送次数为："+order.getPushCount());
						res = cashierEncashOrderDao.updatePushResultCount(orderId); // 更新推送失败次数
						if (res<=0) {
							logger.info("更新提现推送次数失败！orderId="+orderId+",pushCount="+order.getPushCount());
						}
					}
				} catch (Exception e1) {
					logger.error("updatePushFail/updatePushResultCount 异常",e1);
					throw ICashierServiceException.systemException;
				}
            }
            if(e instanceof BizException){
                throw (BizException)e;
            }
            
        }
        
    }


    //用收银台私钥加密
    @Override
    public String genEncashSign(String orderId, String platId, String userId, String partnerId, String moneyStr, String returnCode) {
        String split = ICashierEnumConst.EncryptStrCentor.COMMON.getCode();
        StringBuffer msg = new StringBuffer();
        Encryptor encrytor = EncryptorManager.getEncryptor("partner");
        String cashierId = Configure.getStringValue("encrypt.cashier.id");
        msg = new StringBuffer();
        msg.append(orderId);
        msg.append(split);
        msg.append(platId);
        msg.append(split);
        msg.append(userId);
        msg.append(split);
        msg.append(partnerId);
        msg.append(split);
        msg.append(moneyStr);
        msg.append(split);
        msg.append(returnCode);
        return encrytor.encrypt(cashierId, null, msg.toString());
    }

    @Override
    public boolean validateEncashSign(CashierEncashOrder order) {
        String split = ICashierEnumConst.EncryptStrCentor.COMMON.getCode();
        DecimalFormat df = new DecimalFormat("0.00");
        String moneyStr = df.format(order.getMoney());
        // 验证数据库数据是否被篡改
        StringBuffer msg = new StringBuffer();
        msg.append(moneyStr);
        msg.append(split);
        msg.append(order.getPlatId());
        msg.append(split);
        msg.append(order.getUserId());
        msg.append(split);
        msg.append(order.getOrderId());
        msg.append(split);
        msg.append(order.getSellName());
        msg.append(split);
        msg.append(order.getSellAccount());
        //msg.append(split);
        Encryptor encrytor = EncryptorManager.getEncryptor("partner");
        String encryptedId = Configure.getStringValue("encrypt.cashier.id");
        return encrytor.encryptValidate(encryptedId, null, msg.toString(), order.getSign());
    }


    @Override
    public int updateAccountStatus(String accountId, String orderId, int accountStatus, String accountDay) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("accountId", accountId);
        params.put("orderId", orderId);
        params.put("accountStatus", accountStatus);
        params.put("accountDay", accountDay);
        return cashierEncashOrderDao.updateAccountStatus(params);
    }


    @Override
    public List<CashierEncashOrder> selectThirdLessData(String day, String accountId, int pageNo, int pageSize) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("day", day);
        params.put("accountId", accountId);
        params.put("from", (pageNo-1)*pageSize);
        params.put("size", pageSize);
        return cashierEncashOrderDao.selectThirdLessData(params);
    }


    @Override
    public List<CashierEncashOrder> selectAccountNonDatas(String day, String accountId, int pageNo, int pageSize) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("day", day);
        params.put("accountId", accountId);
        params.put("from", (pageNo-1)*pageSize);
        params.put("size", pageSize);
        return cashierEncashOrderDao.selectAccountNonDatas(params);
    }


    @Override
    public List<CashierEncashOrder> selectByOrderIds(List<String> orderIds) {
        if(CollectionUtils.isEmpty(orderIds)){
            return null;
        }
        return cashierEncashOrderDao.selectByOrderIds(orderIds);
    }


    @Override
    public void updateThirdAccountTime(List<String> orderIds, String accountDay) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("orderIds", orderIds);
        params.put("accountDay", accountDay);
        cashierEncashOrderDao.updateThirdAccountTime(params);
    }
    @Override
    public int queryRefundCount(String accountPeriod) {
        return cashierEncashOrderDao.queryRefundCount(accountPeriod);
    }


    @Override
    public List<String> queryRefundAccountPeriod(String accountPeriod) {
        return cashierEncashOrderDao.queryRefundAccountPeriod(accountPeriod);
    }

    @Override
    public int queryCountByAccountPeriod(String accountPeriod) {
        return cashierEncashOrderDao.queryCountByAccountPeriod(accountPeriod);
    }


    @Override
    public List<CashierEncashOrder> queryAccountByPage(String accountPeriod, int start, int limit) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("accountPeriod", accountPeriod);
        params.put("start", start);
        params.put("limit", limit);
        return cashierEncashOrderDao.queryAccountByPage(params);
    }


    @Override
    public int queryAccountCount(String accountPeriod) {
        return cashierEncashOrderDao.queryAccountCount(accountPeriod);
    }


	@Override
	public List<CashierEncashOrder> queryBatchOrder(String batchId) {
		
		return cashierEncashOrderDao.queryBatchOrder(batchId);
	}


	@Override
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
	public void updateBatchOrder(String batchId, String fileName, int status, Date tradeDay,
                                 String msg) throws Exception {
		int i = 0;
		List<CashierEncashOrder> batchOrder = queryBatchOrder(batchId);
		for (CashierEncashOrder cashierEncashOrder : batchOrder) {
			i = updateEncashResult(cashierEncashOrder.getOrderId(), status, tradeDay,msg);
			if (i<=0) {
				throw new Exception("updateEncashResult exception batchId="+batchId+",orderId="+cashierEncashOrder.getOrderId());
			}
			pushEncashOrder(cashierEncashOrder.getOrderId());
		}
		i = cashierEncashBatchService.updateToFinish(fileName);
		if (i<=0) {
			throw new Exception("updateToFinish exception batchId="+batchId+",fileName="+fileName);
		}
	}

}
